home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 / Ham Radio 2000.iso / ham2000 / tcp_ip / os2 / pmnos11s / nntpserv.c < prev    next >
C/C++ Source or Header  |  1993-07-30  |  56KB  |  2,624 lines

  1. /*
  2.  *
  3.  * NNTP Server/Client - See RFC977
  4.  * Jeffrey R. Comstock. - NR0D - Bloomington, Minnesota USA
  5.  * Copyright 1990 Jeffrey R. Comstock, All Rights Reserved.
  6.  * Permission granted for non-commercial copying and use, provided
  7.  * this notice is retained.
  8.  *
  9.  * DB3FL 9107xx: heavily rewritten and bug fixing in file-handling
  10.  *
  11.  * ported to NOS by PE1NMB - 920120
  12.  *
  13.  * Mods by PA0GRI and WG7J
  14.  */
  15.  
  16. #include <stdio.h>
  17. #include <time.h>
  18. #include <stdarg.h>
  19. #include <ctype.h>
  20. #include <setjmp.h>
  21. #include <errno.h>
  22. #if !defined(OS2)
  23. #include <dos.h>
  24. #include <dir.h>
  25. #include <io.h>
  26. #endif
  27. #include <sys\stat.h>
  28. #include <string.h>
  29. #include "global.h"
  30. #include "config.h"
  31. #ifdef NNTPS
  32. #include "mbuf.h"
  33. #include "cmdparse.h"
  34. #include "socket.h"
  35. #include "iface.h"
  36. #include "proc.h"
  37. #include "smtp.h"
  38. #include "commands.h"
  39. #include "dirutil.h"
  40. #include "ftp.h"
  41. #include "netuser.h"
  42. #include "nntp.h"
  43. #include "session.h"
  44. #include "files.h"
  45. #include "smtp.h"
  46. #include "bm.h"
  47. #ifdef LESS_WHINING
  48. #include "pc.h"
  49. #include "usock.h"
  50. #include "nr4.h"
  51. #include "netrom.h"
  52. #include "udp.h"
  53. #include "tcp.h"
  54. #include "ip.h"
  55. #endif
  56.  
  57. int setintrc __ARGS((int16 *var,char *label,int argc, char *argv[],int minval,int16 maxval));
  58. FILE *open_file __ARGS((char *name,char *mode,int s,int t));
  59. FILE *temp_file __ARGS((int s,int t));     /*                            NMB */
  60.  
  61. /***************************************************************************/
  62.  
  63.  
  64. #undef CONTROL                /* reverse NNTP function (not implemented yet) */
  65. #define    LINE    80
  66.  
  67. static int Snntp = -1;      /* prototype socket for service */
  68. static int16 Nntpquiet = 0;
  69. int Filecheck = 0;            /* flag if file system has been checked */
  70.  
  71. struct post *Post = NULLPOST;
  72. struct Servers *Nntpserver = NULLSERVER;
  73.  
  74. static char *Host    = NULLCHAR;
  75. static char NEol[]     = ".\n";
  76.  
  77. /*############################ NNTP COMMANDS #################################*/
  78.  
  79. /* Command table */
  80. static char *commands[] = {
  81.     "quit",
  82. #define QUIT_CMD    0
  83.     "help",
  84. #define HELP_CMD    1
  85.     "list",
  86. #define LIST_CMD    2
  87.     "group",
  88. #define GROUP_CMD    3
  89.     "debug",
  90. #define DEBUG_CMD    4
  91.     "article",
  92. #define ARTICLE_CMD    5
  93.     "next",
  94. #define NEXT_CMD    6
  95.     "xinfo",
  96. #define XINFO_CMD    7
  97.     "ihave",
  98. #define IHAVE_CMD    8
  99.     "newnews",
  100. #define NEWNEWS_CMD    9
  101.     "head",
  102. #define HEAD_CMD    10
  103.     "body",
  104. #define BODY_CMD    11
  105.     "stat",
  106. #define STAT_CMD    12
  107.     "last",
  108. #define LAST_CMD    13
  109.     "slave",
  110. #define SLAVE_CMD    14
  111.     NULLCHAR
  112. };
  113.  
  114. static char artmsg[]     = " Article retrieved - ";
  115.  
  116. static char info[]    = "100 %s Info:\n";
  117. static char xinfo[]    = "100 No info available\n";
  118. static char debug[]    = "100 DEBUG %s\n";
  119.  
  120. static char nnversion[]    = "20%s %s NNTP version %s ready at %s\n";
  121. static char slave[]        = "202 SLAVE %s\n";
  122. static char closing[]    = "203 Closing\n";
  123. static char listarticle[]= "211 %u %u %u%s\n";
  124. static char retrieve[]     = "220 %u%s%shead and body follow\n";
  125. static char head[]    = "221 %u%s%sHead\n";
  126. static char body[]    = "222 %u%s%sBody\n";
  127. static char statistics[]= "223 %u%s%sStatistics\n";
  128. static char sepcmd[]    = "223 %u%s%srequest text separately\n";
  129. static char newnews_t[]    = "230 New news by message id follows\n";
  130. static char transok[]    = "235 Thanks\n";
  131.  
  132. static char sendart[]    = "335 Send article, end with .\n";
  133.  
  134. static char nogroup[]    = "411 No such newsgroup\n";
  135. static char noselect[]    = "412 No newsgroup selected\n";
  136. static char nonext[]    = "421 No next article\n";
  137. static char noprev[]    = "422 No previous article\n";
  138. static char noart[]    = "430 No such article\n";
  139. static char notwanted[]    = "435 Article not wanted - do not send it\n";
  140. static char transnotok[]= "437 Article rejected - header garbled - do not try again\n";
  141.  
  142. static char badsyntax[]    = "501 Syntax error\n";
  143. static char error[]    = "503 Command not performed\n";
  144. static char nospace[]    = "503 Not enough disk space left\n";
  145. static char lowmem[]    = "503 System overloaded\n";
  146. static char fatal[]    = "503 Fatal error FILE %s\n";
  147.  
  148. static char quitcmd[]    = "QUIT\n";
  149. static char help[]    = "NNTP Server 1992,\n\n"
  150.             "100 ARTICLE  BODY  GROUP   HEAD  HELP IHAVE\n"
  151.              "100 LAST     LIST  NEWNEWS NEXT  QUIT STAT\n";
  152.  
  153. static void
  154. rip2(register char *s)
  155. {
  156.     register char *cp;
  157.  
  158.     if((cp = strpbrk(s,"\r\n")) != NULLCHAR)
  159.         *cp = '\0';
  160. }
  161.  
  162. /* main directory-creating routine
  163.  * handles special chars in pathname - especially for MSDOS
  164.  * returncode: -1 error; 0 success
  165.  */
  166. static int
  167. make_dir(path,s)
  168. char *path;
  169. int s;
  170. {
  171.     register char *cp;
  172.  
  173.     if(path == NULLCHAR)
  174.         return -1;
  175. #ifdef MSDOS
  176.     while((cp = strchr(path,'\\')) != NULLCHAR)
  177.         *cp = '/';
  178. #endif
  179.     if (access(path,0)) {
  180.         if (mkdir(path)) {
  181.             tprintf("Can't create %s: %s\n",path,strerror(errno));
  182.             if(s)
  183.                 usprintf(s,fatal,path);
  184.             return -1;
  185.         }
  186.     }
  187.     return 0;
  188. }
  189.  
  190. /* main message-opening routine
  191.  * returncode: NULLFILE if error; filepointer success */
  192. static FILE *
  193. open_message(mp,f)
  194. struct nntpsv *mp;
  195. FILE *f;
  196. {
  197.     char line[LineLen];
  198.  
  199.     /* mp already checked */
  200.  
  201.     if(f != NULLFILE)
  202.         fclose(f);
  203.  
  204.     sprintf(line,"%s/%u",mp->path,mp->pointer);
  205.  
  206.     if ((f = open_file(line,READ_TEXT,0,0)) == NULLFILE)
  207.         usputs(mp->s,noart);
  208.     return f;
  209. }
  210.  
  211. /* file-receiving routine
  212.  * returncode: -1 if error or 'recvline' faults; 0 success; 1 if blank line */
  213. static int
  214. recv_file(fp,s)
  215. FILE *fp;
  216. int s;
  217. {
  218.     char line[LineLen];
  219.     int check = 0;
  220.  
  221.     for (;;) {
  222.         if (recvline(s,line,LineLen) == -1)
  223.             return -1;
  224.         rip2(line);
  225.         if (strcmp(line,".") == 0) {
  226.             return 0;
  227.         }
  228.         if(!check) {                  /* only enabled on first line! */
  229.             check = 1;
  230.             if (*line == '\0')         /* check for blank line */
  231.                 return 1;
  232.         }
  233.         fprintf(fp,"%s\n",line);
  234.     }
  235. }
  236.  
  237. /* checks incoming article-id against existing articles
  238.  * returncode: -1 if error; 1 if article exists; 0 no article found */
  239. static int
  240. check_article(id)
  241. char *id;
  242. {
  243.     char *p, line[LineLen];
  244.     FILE *f;
  245.  
  246.     if(id == NULLCHAR || (p = strchr(id,'<')) == NULLCHAR
  247.       || (f = open_file(History,READ_TEXT,0,1)) == NULLFILE)
  248.         return -1;
  249.  
  250.     for(;;) {
  251.         if (fgets(line,LineLen,f) == NULL) {
  252.             fclose(f);
  253.             return 0;
  254.         }
  255.         if (strstr(line,p) != NULL) {
  256.             fclose(f);
  257.             return 1;
  258.         }
  259.     }
  260. }
  261.  
  262. /* checks for not valid chars in a line
  263.  * returncode: 0 if valid; 1 if invalid */
  264. static int
  265. check_blank(bp)
  266. char *bp;
  267. {
  268.     if (strpbrk(bp,"!@#$%^&*()_+=<>,./?~`[]{}\|0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") == NULL)
  269.         return 1;
  270.     return 0;
  271. }
  272.  
  273. /* main file-checking routine
  274.  * returncode: -1 if error; 0 success */
  275. static int
  276. check_file(char *path)
  277. {
  278. FILE *hFile;
  279.     if(path == NULLCHAR)
  280.         return -1;
  281.     if(access(path,0)) {
  282.       hFile = fopen(path, "W");
  283.       if (hFile)
  284.          fclose(hFIle);
  285.       }
  286.     return 0;
  287. }
  288.  
  289. /* checks if two spaces exists in given string
  290.  * returncode: -1 if error; 1 success */
  291. static int
  292. check_one(char *str)
  293. {
  294.     register char *cp;
  295.  
  296.     if(str == NULLCHAR || (cp = strchr(str,' ')) == NULLCHAR)
  297.         return -1;
  298.     cp++;
  299.  
  300.     if (strchr(cp,' ') == NULLCHAR)
  301.         return -1;
  302.  
  303.     return 1;
  304. }
  305.  
  306. /* checks the file-system used for NNTP
  307.  * returncode: -1 if error; 0 success - and "Filecheck" is set to 1 */
  308. static int
  309. check_system(void)
  310. {
  311.     FILE *f;
  312.     char line[LineLen];
  313.     int error = 0;
  314.  
  315.     if (Post == NULLPOST)
  316.         donnprofile(10,NULL,NULL);
  317.  
  318.     if(Filecheck)
  319.         return 0;
  320.  
  321.     error  = make_dir(Forward,0);
  322.     error |= check_file(Pointer);
  323.     error |= check_file(History);
  324.     error |= check_file(Active);
  325.     error |= check_file(Poll);
  326.  
  327.     if(error)
  328.         goto quit;
  329.  
  330.     sprintf(line,"%s/fwd.seq",Newsdir);
  331.     if (access(line,0)) {
  332.         if((f = open_file(line,"w+",0,1)) == NULLFILE) {
  333.             goto quit;
  334.         }
  335.         fputs("1\n",f);
  336.         fclose(f);
  337.     }
  338.     sprintf(line,"%s/sequence.seq",Mailqdir);
  339.     if (access(line,0)) {
  340.         if((f = open_file(line,"w+",0,1)) == NULLFILE) {
  341.             goto quit;
  342.         }
  343.         fputs("1\n",f);
  344.         fclose(f);
  345.     }
  346.     Filecheck = 1;
  347.     return 0;
  348.  
  349. quit:
  350.     Filecheck = 0;
  351.     tputs("Error in NNTP file system\n");
  352.     return -1;
  353. }
  354.  
  355. /* handles the response code of an incoming msg
  356.  * returncode: -1 error; 0 no code; value of response code on success */
  357. static int
  358. getreply(cb)
  359. struct nntpsv *cb;
  360. {
  361.     int response;
  362.  
  363.     while(recvline(cb->s,cb->buf,LineLen) != -1) {
  364.         /* skip informative messages and blank lines */
  365.         if(cb->buf[0] == '\0' || cb->buf[0] == '1')
  366.             continue;
  367.         sscanf(cb->buf,"%d",&response);
  368.         return (response < 500) ? response : -1;
  369.     }
  370.     return -1;
  371. }
  372.  
  373. /* returncode: -1 error; 1 success; 0 no entry */
  374. static int
  375. get_path(group,mp)
  376. char *group;
  377. struct nntpsv *mp;
  378. {
  379.     FILE *f;
  380.     char line[LineLen], *cp;
  381.  
  382.     if(group == NULLCHAR || mp == NULLNNTPSV
  383.       || (f = open_file(Pointer,READ_TEXT,mp->s,0)) == NULLFILE)
  384.         return -1;
  385.  
  386.     group++;
  387.  
  388.     for (;;) {
  389.         if (fgets(line,LineLen,f) == NULL)
  390.             break;
  391.         if (strcspn(line," ") != strlen(group))
  392.             continue;
  393.         if (strnicmp(group,line,strlen(group)) == 0) {
  394.             cp = (strchr(line,' ')) + 1;
  395.             if (mp->path != NULLCHAR)
  396.                 free(mp->path);
  397.             mp->path = strdup(cp);
  398.             rip2(mp->path);
  399.             fclose(f);
  400.             return 1;
  401.         }
  402.     }
  403.     fclose(f);
  404.     return 0;
  405. }
  406.  
  407. /* checkes if path to given article exists
  408.  * returncode: -1 error; 1 success; 0 no path */
  409. static int
  410. get_path2(art)
  411. struct article *art;
  412. {
  413.     FILE *f;
  414.     char line[LineLen], *p;
  415.  
  416.     if(art->group == NULLCHAR
  417.       || (f = open_file(Pointer,READ_TEXT,0,1)) == NULLFILE)
  418.         return -1;
  419.  
  420.     p = art->group;
  421.     art->path = NULLCHAR;
  422.  
  423.     for (;;) {
  424.         if (fgets(line,LineLen,f) == NULL)
  425.             break;
  426.         if (strcspn(line," ") != strlen(p))
  427.             continue;
  428.         if (strnicmp(p,line,strlen(p)) == 0) {
  429.             p = (strchr(line,' ')) + 1;
  430.             if(art->path != NULLCHAR)
  431.                 free(art->path);
  432.             art->path = strdup(p);
  433.             rip2(art->path);
  434.             fclose(f);
  435.             return 1;
  436.         }
  437.     }
  438.     fclose(f);
  439.     return 0;
  440. }
  441.  
  442. /* returncode: -1 if error; 1 success; 0 no pointer */
  443. static int
  444. get_pointer(group,mp)
  445. char *group;
  446. struct nntpsv *mp;
  447. {
  448.     FILE *f;
  449.     char line[LineLen], *p;
  450.  
  451.     if(group == NULLCHAR || mp == NULLNNTPSV
  452.       || (f = open_file(Active,READ_TEXT,mp->s,0)) == NULLFILE)
  453.         return -1;
  454.  
  455.     group++;
  456.  
  457.     for (;;) {
  458.         if (fgets(line,LineLen,f) == NULL)
  459.             break;
  460.         if (strcspn(line," ") != strlen(group))
  461.             continue;
  462.         if (strnicmp(group,line,strlen(group))==0) {
  463.             p = strchr(line,' ');
  464.             mp->last = (unsigned)atoi(p);
  465.             p++;
  466.             mp->first = (unsigned)atoi(strchr(p,' '));
  467.             mp->pointer = (mp->first > mp->last ) ? 0 : mp->first;
  468.             fclose(f);
  469.             return 1;
  470.         }
  471.     }
  472.     fclose(f);
  473.     return 0;
  474. }
  475.  
  476. /* creating path to a new newsgroup
  477.  * handling of "." and "\" in pathnames especially MSDOS */
  478. /* returncode: -1 error; 0 success */
  479. static int
  480. make_path(group)
  481. char *group;
  482. {
  483.     FILE *f;
  484.     char cp[LineLen], cp1[LineLen], *cp2;
  485.     int got_it;
  486.  
  487.     if (group == NULLCHAR
  488.       || (f = open_file(Pointer,APPEND_TEXT,0,1)) == NULLFILE)
  489.         return -1;
  490.  
  491.     got_it = 0;
  492.     strcpy(cp1,group);
  493.  
  494.     for(;;) {
  495.         if((cp2 = strchr(cp1,'.')) != NULLCHAR)
  496.             *cp2 = '\0';
  497.         else
  498.             got_it = 1;
  499.  
  500.         sprintf(cp,"%s/%s",Newsdir,cp1);
  501.  
  502.         if(make_dir(cp,0)) {
  503.             fclose(f);
  504.             return -1;
  505.         }
  506.         if(got_it) {
  507.             fprintf(f,"%s %s\n",group,cp);
  508.             fclose(f);
  509.             return 0;
  510.         }
  511.         *cp2 = '/';
  512.     }
  513. }
  514.  
  515. static int
  516. update_list(a)
  517. struct nntpsv *a;
  518. {
  519.     FILE *f, *t;
  520.     char *p, *p1, l2[LineLen];
  521.  
  522.     if((f = open_file(Active,READ_TEXT,a->s,0)) == NULLFILE)
  523.         return -1;
  524.  
  525.     if ((t = temp_file(0,1)) == NULLFILE) {
  526.         fclose(f);
  527.         return -1;
  528.     }
  529.     p1 = a->ap->group;
  530.     a->ap->number = 0;
  531.     for (;;) {
  532.         if (fgets(a->buf,LineLen,f) == NULL)
  533.             break;
  534.         a->ap->tmpu = strcspn(a->buf," ");
  535.         strncpy(l2,a->buf,a->ap->tmpu);
  536.         l2[a->ap->tmpu] = '\0';
  537.         if (strcmp(p1,l2) == 0) {
  538.             p = strchr(a->buf,' ') + 1;
  539.             a->ap->number = (unsigned)atoi(p);
  540.             (a->ap->number)++;
  541.             p = strchr(p,' ');
  542.             fprintf(t,"%s %5.5u%s",p1,a->ap->number,p);
  543.         } else
  544.             fputs(a->buf,t);
  545.     }
  546.     fclose(f);
  547.     rewind(t);
  548.     if ((f = open_file(Active,WRITE_TEXT,a->s,0)) == NULLFILE) {
  549.         fclose(t);
  550.         return -1;
  551.     }
  552.     for(;;) {
  553.         if (fgets(a->buf,LineLen,t) == NULL)
  554.             break;
  555.         fputs(a->buf,f);
  556.     }
  557.     fclose(t);
  558.     if (a->ap->number == 0) {
  559.         make_path(a->ap->group);
  560.         a->ap->number = 1;
  561.         fprintf(f,"%s 00001 00001 y\n",a->ap->group);
  562.     }
  563.     fclose(f);
  564.     return (a->ap->number);
  565. }
  566.  
  567. /* returncode: -1 error; 0 success */
  568. static int
  569. dup_f(in,out,mp)
  570. FILE *in;
  571. FILE *out;
  572. struct nntpsv *mp;
  573. /* Path: bug in col 1 of article body bug fixed by G4JEC 901019....*/
  574. {
  575.     char *p;
  576.     int blank_line_flag = 1;
  577.  
  578.     for(;;) {
  579.         if (fgets(mp->buf,LineLen,in) == NULL)
  580.             return 0;
  581.  
  582.         if (blank_line_flag)
  583.             if (strnicmp(mp->buf,Hdrs[PATH],5) == 0) {
  584.                  p = strchr(mp->buf,' ') + 1;
  585.                  fprintf(out,"%s%s!%s",Hdrs[PATH],Host,p);
  586.                  continue;
  587.             }
  588.         /* oh oh - nntpserv is modifying articles....*/
  589.         if (strlen(mp->buf) == 1 && mp->buf[0] == '.')
  590.             continue;
  591.         fputs(mp->buf,out);
  592.         if(!check_blank(mp->buf))
  593.             blank_line_flag = 0;
  594.     }
  595. }
  596.  
  597. /* returncode: < 1 if error; 1 success */
  598. static int
  599. dofwd(mp,f,history)
  600. struct nntpsv *mp;
  601. FILE *f;
  602. FILE *history;
  603. {
  604.     FILE *fwd;
  605.  
  606.     if(mp == NULLNNTPSV)
  607.         return -1;
  608.  
  609.     sprintf(mp->buf,"%s/fwd.seq",Newsdir);
  610.     if ((fwd = open_file(mp->buf,"r+",mp->s,0)) == NULLFILE)
  611.         return -1;
  612.  
  613.     fgets(mp->buf,LineLen,fwd);
  614.     mp->hold_i = atoi(mp->buf) + 1;
  615.     fprintf(history," JUNK/%u",mp->hold_i);
  616.     rewind(fwd);
  617.     fprintf(fwd,"%u",mp->hold_i);
  618.     fclose(fwd);
  619.  
  620.     sprintf(mp->buf,"%s/%u",Forward,mp->hold_i);
  621.     if ((fwd = open_file(mp->buf,WRITE_TEXT,mp->s,0)) == NULLFILE)
  622.         return -2;
  623.  
  624.     rewind(f);
  625.     dup_f(f,fwd,mp);
  626.     fclose(fwd);
  627.     return 1;
  628. }
  629.  
  630. #ifdef CONTROL
  631. static int
  632. docontrol(f,mp)
  633. FILE *f;
  634. struct nntpsv *mp;
  635. {
  636.     struct head *h;
  637.  
  638.     if(f == NULLFILE || mp == NULLNNTPSV
  639.       || (h = (struct head *)callocw(1,sizeof(struct head))) == NULLHEAD))
  640.         return -1;
  641.  
  642.     rewind(f);
  643.     h->subject = h->from = h->reply_to = h->id = NULLCHAR;
  644.  
  645.     for(;;) {
  646.         if ((fgets(mp->buf,LineLen,f)) == NULL)
  647.             break;
  648.         if (check_blank(mp->buf))
  649.             break;
  650.         rip2(mp->buf);
  651.         if (strncmp(mp->buf,Hdrs[SUBJECT],9) == 0)
  652.             h->subject = strdup(mp->buf);
  653.         if (strncmp(mp->buf,Hdrs[FROM],6) == 0)
  654.             h->from = strdup(mp->buf);
  655.         if (strnicmp(mp->buf,Hdrs[REPLYTO],10) == 0)
  656.             h->reply_to = strdup(mp->buf);
  657.         if (strnicmp(mp->buf,Hdrs[MSGID],12) == 0)
  658.             h->id = strdup(strchr(mp->buf,'<'));
  659.     }
  660.     if (h->subject != NULLCHAR)
  661.         if (strncmp(h->subject,"Subject: sendme ",16) == 0)
  662.             dosendme(h);
  663.     if (h->subject != NULLCHAR)
  664.         free(h->subject);
  665.     if (h->from != NULLCHAR)
  666.         free(h->from);
  667.     if (h->reply_to != NULLCHAR)
  668.         free(h->reply_to);
  669.     if (h->id != NULLCHAR)
  670.         free(h->id);
  671.     free((char *)h);
  672.     return 0;
  673. }
  674. #endif
  675.  
  676. static int
  677. xfer_article2(f,mp)
  678. FILE *f;
  679. struct nntpsv *mp;
  680. {
  681.     char line[LineLen], *p, *group = NULLCHAR, *p1, *from = NULLCHAR;
  682.     FILE *fptr, *history;
  683.     struct tm *stm;
  684.     int x;
  685. #ifdef CONTROL
  686.     int control = 0;
  687. #endif
  688.     long currtime;
  689.  
  690.     if(f == NULLFILE || mp == NULLNNTPSV ||
  691.       (history = open_file(History,APPEND_TEXT,mp->s,0)) == NULLFILE)
  692.         return -1;
  693.  
  694.     for (;;) {
  695.         if (fgets(line,LineLen,f) == NULL)
  696.             break;
  697.         rip2(line);
  698.         if (strnicmp(line,Hdrs[FROM],6) == 0) {
  699.             p = strchr(line,' ') + 1;
  700.             from = strdup(p);
  701.             continue;
  702.         }
  703.         if (strnicmp(line,Hdrs[NEWSGROUPS],12) == 0) {
  704.             p = strchr(line,' ') + 1;
  705.             group = strdup(p);
  706.             break;
  707.         }
  708.     }
  709.     time(&currtime);
  710.     stm = localtime(&currtime);
  711.     fprintf(history,"%s %2.2d%2.2d%2.2d %2.2d%2.2d%2.2d",
  712.         mp->id,
  713.         stm->tm_year,stm->tm_mon+1,stm->tm_mday,
  714.         stm->tm_hour,stm->tm_min,stm->tm_sec);
  715.  
  716.     mp->hold_i = 0;
  717.     p = group;
  718.     if((mp->ap = (struct article *)callocw(1,sizeof(struct article))) == NULLARTICLE)
  719.         goto quit;
  720.     x = 1;
  721.     while (x) {
  722.         if ((p1 = strchr(p,',')) != NULLCHAR) {
  723.             p1 = line;
  724.             while (*p != ',')
  725.                 *(p1++)=*(p++);
  726.             *p1 = '\0';
  727.             p++;
  728.             mp->ap->group = strdup(line);
  729.         } else {
  730.             mp->ap->group = strdup(p);
  731.             x = 0;
  732.         }
  733.         update_list(mp);
  734.         if (mp->ap->number > 0) {
  735.             get_path2(mp->ap);
  736.             mp->hold_i = 1;
  737.             sprintf(line,"%s/%u",mp->ap->path,mp->ap->number);
  738.             rewind(f);
  739.             if ((fptr = open_file(line,WRITE_TEXT,mp->s,0)) == NULLFILE) {
  740.                 fclose(history);
  741.                 free(mp->ap->group);
  742.                 goto quit;
  743.             }
  744.             dup_f(f,fptr,mp);
  745.             fclose(fptr);
  746.             fprintf(history," %s/%d",mp->ap->group,mp->ap->number);
  747. #ifdef CONTROL
  748.             if (strcmp(mp->ap->group,"control") == 0)
  749.                 control = 1;
  750. #endif
  751.             free(mp->ap->path);
  752.         }
  753.         free(mp->ap->group);
  754.     }
  755.     if (mp->hold_i == 0) {
  756.         if ((x = dofwd(mp,f,history)) < 1)
  757.         mp->hold_i = 0;
  758.     }
  759.     fputc('\n',history);
  760.     fclose(history);
  761.     time(&currtime);
  762.     if(Nntpquiet < 2)
  763.         tprintf("New mail in newsgroup %s\n  from <%s> at %s%s",
  764.             group,from,ctime(&currtime),
  765.             (Nntpquiet < 1)  ? "\007" : "");
  766.  
  767. #ifdef CONTROL
  768.     if (control == 1)
  769.         docontrol(f,mp);
  770. #endif
  771. quit:
  772.     free(from);
  773.     free(group);
  774.     free((char *)mp->ap);
  775.     return 1;
  776. }
  777.  
  778. static void
  779. nntppoll(unused,cb1,p)
  780. int unused;
  781. void *cb1;
  782. void *p;
  783. {
  784.     char *cp, line[LineLen];
  785.     struct sockaddr_in fsocket;
  786.     struct nntpsv *cb;
  787.     struct tm *stm, *ltm;
  788.     FILE *f, *f1, *pf;
  789.     long t;
  790.     int r, now;
  791.     struct Servers *sp = (struct Servers *) cb1;
  792.     long currtime;
  793.  
  794.     if (!run_timer(&sp->nntpt))        /* if timer had stopped there is an
  795.         return;                         * active session */
  796.  
  797.     if (!Filecheck)
  798.         if(check_system())
  799.             return;
  800.  
  801.     if(availmem() < Memthresh) {
  802.         start_timer(&sp->nntpt);
  803.         return;
  804.     }
  805.  
  806.     /* check connection window */
  807.     time(&currtime);
  808.     ltm = localtime(&currtime);
  809.     now = ltm->tm_hour * 100 + ltm->tm_min;
  810.     if (sp->lowtime < sp->hightime) {
  811.         /* doesn't cross midnight */
  812.         if (now < sp->lowtime || now >= sp->hightime) {
  813.             start_timer(&sp->nntpt);
  814.             return;
  815.         }
  816.     } else {
  817.         if (now < sp->lowtime && now >= sp->hightime) {
  818.             start_timer(&sp->nntpt);
  819.             return;
  820.         }
  821.     }
  822.     if((pf = open_file(Poll,"r+",0,1)) == NULLFILE ||
  823.       (cb = (struct nntpsv *)callocw(1,sizeof(struct nntpsv))) == NULLNNTPSV) {
  824.         start_timer(&sp->nntpt);
  825.         return;
  826.     }
  827.     stop_timer(&sp->nntpt);
  828.  
  829.     cb->fname = NULLCHAR;
  830.     cb->newnews = NULLCHAR;
  831.     rewind(pf);
  832.  
  833.     for(t = 0L; fgets(line,LineLen,pf) != NULLCHAR; t = ftell(pf)) {
  834.         if((cp = strchr(line,' ')) == NULLCHAR)
  835.             continue;        /* something wrong with this line, skip it */
  836.         *cp = '\0';
  837.         if(strnicmp(line,sp->name,strcspn(line," ")-1) == 0) {
  838.             rip2(cp+1);
  839.             cb->newnews = strdup(cp+1);
  840.             /* Prepare to write back the current host and date */
  841.             fseek(pf,t,0);
  842.             break;
  843.         }
  844.     }
  845.  
  846.     if(cb->newnews == NULLCHAR)
  847.          cb->newnews = strdup("800101 000000");
  848.  
  849.     fsocket.sin_family = AF_INET;
  850.     fsocket.sin_addr.s_addr = cb->dest = sp->dest;
  851.     fsocket.sin_port = IPPORT_NNTP;
  852.  
  853.     if((cb->s = socket(AF_INET,SOCK_STREAM,0)) == -1)
  854.         goto quit;
  855.     sockmode(cb->s,SOCK_ASCII);
  856.  
  857.     if(connect(cb->s,(char *)&fsocket,SOCKSIZE) == -1)
  858.         goto quit;
  859.     log(cb->s,"Connect NNTP");
  860.  
  861.     time(&currtime);
  862.     stm = localtime(&currtime);
  863.  
  864.     if(getreply(cb) == -1)      /* throw away any hello msg */
  865.         goto quit;
  866.  
  867. #ifdef XXX
  868.     usputs(cb->s,"SLAVE\n");
  869.     if(getreply(cb) != 202)
  870.         goto quit;
  871. #endif
  872.     cb->slave = 1;
  873.  
  874.     if ((f = temp_file(0,1)) == NULLFILE)
  875.         goto quit;
  876.  
  877.     usprintf(cb->s,"NEWNEWS %s %s\n",sp->newsgroups,cb->newnews);
  878.     if(getreply(cb) != 230) {
  879.         fclose(f);
  880.         goto quit;
  881.     }
  882.     if(recv_file(f,cb->s) == -1) {
  883.         usprintf(cb->s,quitcmd);
  884.         fclose(f);
  885.         goto quit;
  886.     }
  887.     if ((f1 = temp_file(cb->s,1)) == NULLFILE) {
  888.         fclose(f);
  889.         goto quit;
  890.     }
  891.     rewind(f);
  892.  
  893.     for(;;) {
  894.         if (fgets(cb->buf,LineLen,f) == NULL)
  895.             break;
  896.         rip2(cb->buf);
  897.         if (strcmp(cb->buf,".") == 0)
  898.             break;
  899.         if (check_article(cb->buf) == 1)
  900.             continue;
  901.         usprintf(cb->s,"ARTICLE %s\n",cb->buf);
  902.         for (;;) {
  903.             if ((r = recvline(cb->s,cb->buf,LineLen)) == -1)
  904.                 break;
  905.             rip2(cb->buf);
  906.             if(!isdigit(cb->buf[0])) {
  907.                 r = -1;
  908.                 continue;
  909.             } else {
  910.                 r = atoi(cb->buf);
  911.                 break;
  912.             }
  913.         }
  914.         if(r == -1)
  915.             break;
  916.         if (r == 220) {
  917.             recv_file(f1,cb->s);
  918.             rewind(f1);
  919.             for ( ;; ) {
  920.                 if (fgets(cb->buf,LineLen,f1) == NULL)
  921.                     break;
  922.                 rip2(cb->buf);
  923.                 if (strnicmp(cb->buf,Hdrs[MSGID],12) == 0) {
  924.                     cb->id = strdup((strchr(cb->buf,' ')) + 1);
  925.                     break;
  926.                 }
  927.             }
  928.             rewind(f1);
  929.             xfer_article2(f1,cb);
  930.             free(cb->id);
  931.         }
  932.         fclose(f1);
  933.         if ((f1 = temp_file(cb->s,1)) == NULLFILE)
  934.             goto quit;
  935.     }
  936.     fclose(f);
  937.     fclose(f1);
  938.     usprintf(cb->s,quitcmd);
  939.     if (recvline(cb->s,cb->buf,LineLen) == -1)
  940.         goto quit;
  941. quit:
  942.     if(errno == 0) {
  943.         /* Now write back the opening date and time */
  944.         fprintf(pf,"%s %02d%02d%02d %02d%02d%02d\n",
  945.             sp->name,
  946.             stm->tm_year,
  947.             stm->tm_mon + 1,
  948.             stm->tm_mday,
  949.             stm->tm_hour,
  950.             stm->tm_min,
  951.             stm->tm_sec);
  952.     }
  953.     fclose(pf);
  954.  
  955.     close_s(cb->s);
  956.     free(cb->newnews);
  957.     free((char *)cb);
  958.     start_timer(&sp->nntpt);
  959. }
  960.  
  961. static int
  962. ngmatcha(func,dflt,ngspec,matchlist)
  963. int    (*func)();
  964. int    dflt;
  965. struct g_list *ngspec;
  966. struct g_list *matchlist;
  967. {
  968.     register int    match;
  969.     char   *cp;
  970.     struct g_list    *m,*n;
  971.  
  972.     match = dflt;
  973.     m = matchlist;
  974.     for(;;) {
  975.         if ((cp = strchr(m->str,'/')) != NULLCHAR)
  976.             *cp = '\0';
  977.         n = ngspec;
  978.         for (;;) {
  979.             if (n->str[0] == '!') {      /* Handle negation */
  980.                 if ((*func)(n->str+1, m->str)) {
  981.                     match = 0;
  982.                 }
  983.             } else {
  984.                 if ((*func)(n->str, m->str)) {
  985.                     match = 1;
  986.                 }
  987.             }
  988.             if (n->next == NULLG)
  989.                 break;
  990.             else
  991.                 n=n->next;
  992.         }
  993.         if (m->next == NULLG)
  994.             break;
  995.         else
  996.             m=m->next;
  997.     }
  998.     return (match);
  999. }
  1000.  
  1001. static int
  1002. restreql(w, s)
  1003. register char *w;
  1004. register char *s;
  1005. {
  1006.     while (*s && *w) {
  1007.         switch (*w) {
  1008.             case '*':
  1009.                 for (w++; *s; s++)
  1010.                     if (restreql(w, s))
  1011.                         return 1;
  1012.                 break;
  1013.             default:
  1014.                 if (*w != *s)
  1015.                     return 0;
  1016.                 w++, s++;
  1017.                 break;
  1018.         }
  1019.     }
  1020.     if (*s)
  1021.         return 0;
  1022.     while (*w)
  1023.         if (*w++ != '*')
  1024.             return 0;
  1025.  
  1026.     return 1;
  1027. }
  1028.  
  1029. /* converts timestring to unix-compatible structure
  1030.  * returncode: 0 (!!) if error; > 0 success */
  1031. static int32
  1032. make_nntime(d,t,str)
  1033. struct date *d;
  1034. struct time *t;
  1035. char *str;
  1036. {
  1037.     register char *cp;
  1038.     char tmp[3];
  1039.  
  1040.     if(str == NULLCHAR)
  1041.         return 0;
  1042.  
  1043.     tmp[2] = '\0';
  1044.     cp = str;
  1045.  
  1046.     strncpy(tmp,cp,2);
  1047.  
  1048.     d->tm_year = atoi(tmp)+1900;
  1049.  
  1050.     if (d->tm_year < 1980)
  1051.         d->tm_year = 1980;
  1052.  
  1053.     if (d->tm_year > 2099)
  1054.         goto quit;
  1055.  
  1056.     cp+=2;
  1057.  
  1058.     strncpy(tmp,cp,2);
  1059.     d->tm_mon = atoi(tmp);
  1060.     if (d->tm_mon < 1 || d->tm_mon > 12)
  1061.         goto quit;
  1062.  
  1063.     cp+=2;
  1064.  
  1065.     strncpy(tmp,cp,2);
  1066.     d->tm_day = atoi(tmp);
  1067.     if (d->tm_day < 1 || d->tm_day > 32)
  1068.         goto quit;
  1069.  
  1070.     cp+=3;
  1071.  
  1072.     strncpy(tmp,cp,2);
  1073.     t->tm_hour = atoi(tmp);
  1074.     if (t->tm_hour < 0 || t->tm_hour > 24)
  1075.         goto quit;
  1076.  
  1077.     cp+=2;
  1078.  
  1079.     strncpy(tmp,cp,2);
  1080.     t->tm_min = atoi(tmp);
  1081.     if (t->tm_min < 0 || t->tm_min > 60)
  1082.         goto quit;
  1083.  
  1084.     cp+=2;
  1085.  
  1086.     strncpy(tmp,cp,2);
  1087.     t->tm_sec = atoi(tmp);
  1088.     if (t->tm_sec < 0 || t->tm_sec > 60)
  1089.         goto quit;
  1090.  
  1091.     return (dostounix(d,t));
  1092. quit :
  1093.     return 0L;
  1094. }
  1095.  
  1096. /* returncode: -1 if error; 0 if no new news; 1 new news available */
  1097. static int
  1098. newnews(string,mp,f)
  1099. char *string;
  1100. struct nntpsv *mp;
  1101. FILE *f;
  1102. {
  1103.     register int i,j;
  1104.     char *cp, *cp1, line[LineLen], groups[LineLen];
  1105.     struct g_list *ng, *hist, *ngp, *histp, *ptr;
  1106.     FILE *f1;
  1107.     int all = 1;
  1108.  
  1109.     if (check_one(string) == -1)
  1110.         return -1;
  1111.  
  1112.     cp = string;
  1113.     i = 1;
  1114.  
  1115.     while (*(cp++) > 32)
  1116.         i++;
  1117.     if (strlen(cp) < 13)
  1118.         return -1;
  1119.  
  1120.     strncpy(groups,string,i-1);
  1121.     groups[i-1] = '\0';
  1122.     if(strcmp(groups,"*") != 0)
  1123.         all = 0;
  1124.  
  1125.     mp->datest = (struct tm *)callocw(1,sizeof(struct tm));
  1126.     mp->timest = (struct tm *)callocw(1,sizeof(struct tm));
  1127.  
  1128.     gettime(mp->timest);
  1129.     getdate(mp->datest);
  1130.  
  1131.     if ((mp->unixtime = make_nntime(mp->datest,mp->timest,cp)) == 0)
  1132.         goto quit;
  1133.     if (mp->unixtime == -1L)
  1134.         return 0;
  1135.  
  1136.     if (!all) {
  1137.         ng = ngp = (struct g_list *)callocw(1,(sizeof(struct g_list)));
  1138.         cp = groups;
  1139.  
  1140.         for (;;) {
  1141.             if ((cp1 = strchr(cp,',')) == NULLCHAR ) {
  1142.                 ng->str = strdup(cp);
  1143.                 ng->next = NULLG;
  1144.                 break;
  1145.             }
  1146.             j = strcspn(cp,",");
  1147.             ng->str = (char *)callocw(1,j+1);
  1148.             strncpy(ng->str,cp,j);
  1149.             ng->str[j] = '\0';
  1150.             ng->next = (struct g_list *)callocw(1,sizeof(struct g_list));
  1151.             ng = ng->next;
  1152.             cp1 = strchr(cp,',');
  1153.             if (cp1 != NULLCHAR)
  1154.                 cp = cp1 + 1;
  1155.             else
  1156.                 break;
  1157.         }
  1158.     }
  1159.  
  1160.     if ((f1 = open_file(History,READ_TEXT,mp->s,0)) == NULLFILE)
  1161.         goto quit;
  1162.  
  1163.     for (;;) {
  1164.         if (fgets(line,LineLen,f1) == NULL)
  1165.             break;
  1166.         rip2(line);
  1167.  
  1168.         if (!all) {
  1169.             for(i = 3, cp = line; i; --i)
  1170.                 cp = strchr(cp,' ') + 1;
  1171.             histp = (struct g_list *)callocw(1,sizeof(struct g_list));
  1172.             hist = histp;
  1173.  
  1174.             for (;;) {
  1175.                 if ((cp1 = strchr(cp,' ')) == NULLCHAR) {
  1176.                     hist->str = strdup(cp);
  1177.                     hist->next = NULLG;
  1178.                     break;
  1179.                 }
  1180.  
  1181.                 j = strcspn(cp," ");
  1182.                 hist->str = (char *)callocw(1,j+1);
  1183.                 strncpy(hist->str,cp,j);
  1184.                 hist->str[j] = '\0';
  1185.                 hist->next = (struct g_list *)callocw(1,sizeof(struct g_list));
  1186.                 hist = hist->next;
  1187.                 cp1 = strchr(cp,' ');
  1188.                 if (cp1 != NULLCHAR)
  1189.                     cp = cp1 + 1;
  1190.                 else
  1191.                     break;
  1192.             }
  1193.             if (!ngmatcha(restreql,0,ngp,histp)) {
  1194.                 ptr = histp;
  1195.                     for (;;) {
  1196.                         ptr = histp->next;
  1197.                         free(histp->str);
  1198.                         free(histp);
  1199.                         histp = ptr;
  1200.                         if (histp == NULLG)
  1201.                             break;
  1202.                     }
  1203.                 continue;
  1204.             }
  1205.         }
  1206.         cp = strchr(line,' ') + 1;
  1207.         if ((mp->ftime = make_nntime(mp->datest,mp->timest,cp)) == 0) {
  1208.             fclose(f1);
  1209.             goto quit;
  1210.         }
  1211.         if ((mp->ftime - mp->unixtime) > 0) {
  1212.             cp = line;
  1213.             while ( *cp > 32 )
  1214.                 fputc(*(cp++),f);
  1215.             fputc('\n',f);
  1216.         }
  1217.         if (!all) {
  1218.             ptr = histp;
  1219.             for (;;) {
  1220.                 ptr = histp->next;
  1221.                 free(histp->str);
  1222.                 free(histp);
  1223.                 histp = ptr;
  1224.                 if (histp == NULLG)
  1225.                     break;
  1226.             }
  1227.         }
  1228.     }
  1229.     fclose(f1);
  1230.     if (!all) {
  1231.         ptr = ngp;
  1232.         for (;;) {
  1233.             ptr = ngp->next;
  1234.             free(ngp->str);
  1235.             free(ngp);
  1236.             ngp = ptr;
  1237.             if (ngp == NULLG)
  1238.                 break;
  1239.         }
  1240.     }
  1241.     free(mp->datest);
  1242.     free(mp->timest);
  1243.     return 1;
  1244. quit:
  1245.     return 0;
  1246. }
  1247.  
  1248. /* handles incoming newnews-cmd
  1249.  * returncode: -1 if error; 0 no groups or bad syntax; 1 success */
  1250. static int
  1251. donewnews(string,mp)
  1252. char *string;
  1253. struct nntpsv *mp;
  1254. {
  1255.     FILE *f;
  1256.     int ret;
  1257.  
  1258.     if((f = temp_file(mp->s,1)) == NULLFILE)
  1259.         return -1;
  1260.  
  1261.     ret = newnews(string,mp,f);
  1262.  
  1263.     switch(ret) {
  1264.     case -1:                        /* error in "newnews" routine */
  1265.         ret = 0;
  1266.         usputs(mp->s,badsyntax);
  1267.         break;
  1268.     case 0:                         /* no new news */
  1269.         usputs(mp->s,newnews_t);
  1270.         usputs(mp->s,NEol);
  1271.         break;
  1272.     default:                        /* new news available, send news file */
  1273.         rewind(f);
  1274.         usputs(mp->s,newnews_t);
  1275.         sendfile(f,mp->s,ASCII_TYPE,0);
  1276.         usputs(mp->s,NEol);
  1277.         ret = 1;
  1278.         break;
  1279.     }
  1280.     fclose(f);
  1281.     return ret;
  1282. }
  1283.  
  1284. /* change current newsgroup
  1285.  * returncode: -1 if error; 0 success; 1 no newsgroup */
  1286. static int
  1287. dogroup(mp,buf)
  1288. struct nntpsv *mp;
  1289. char *buf;
  1290. {
  1291.     char *p;
  1292.     int er;
  1293.  
  1294.     if((p = strchr(buf,' ')) == NULLCHAR)
  1295.         return -1;
  1296.  
  1297.     er = get_path(p,mp);
  1298.  
  1299.     switch (er) {
  1300.     case 0:
  1301.         usputs(mp->s,nogroup);
  1302.         return 1;
  1303.     default:
  1304.         p = strchr(buf,' ');
  1305.         if (get_pointer(p,mp) == 1) {
  1306.             usprintf(mp->s,listarticle,
  1307.                 mp->last - mp->first + 1,mp->first,mp->last,strchr(buf,' '));
  1308.             return 0;
  1309.         }
  1310.     case -1:
  1311.         usputs(mp->s,error);
  1312.         return -1;
  1313.     }
  1314. }
  1315.  
  1316.  
  1317. /* checks if newsgroup is selected
  1318.  * returncode: -1 no group selected; 0 success */
  1319. static int
  1320. check_grp(mp)
  1321. struct nntpsv *mp;
  1322. {
  1323.     if(mp == NULLNNTPSV || mp->path == NULLCHAR) {
  1324.         usputs(mp->s,noselect);
  1325.         return -1;
  1326.     }
  1327.     return 0;
  1328. }
  1329.  
  1330. /* get id-number of message
  1331.  * returncode: -1 if error; 0 if no message; 1 success */
  1332. static int
  1333. get_id(bp,mp)
  1334. char *bp;
  1335. struct nntpsv *mp;
  1336. {
  1337.     FILE *f;
  1338.     char tmp[LineLen];
  1339.  
  1340.     if ((f = open_message(mp,NULLFILE)) == NULLFILE)
  1341.         return 0;
  1342.  
  1343.     for (;;) {
  1344.         if (fgets(tmp,LineLen,f) == NULL)
  1345.             break;
  1346.         if (check_blank(tmp))
  1347.             break;
  1348.         if (strnicmp(tmp,Hdrs[MSGID],12)==0) {
  1349.             fclose(f);
  1350.             strcpy(bp,strchr(tmp,' '));
  1351.             rip2(bp);
  1352.             return 1;
  1353.         }
  1354.     }
  1355.     fclose(f);
  1356.     strcpy(bp,"\0");
  1357.     return 0;
  1358. }
  1359.  
  1360. /* gets next news of newsgroup
  1361.  * returncode: -1 if error; 0 no news; 1 success */
  1362. static int
  1363. get_next(mp)
  1364. struct nntpsv *mp;
  1365. {
  1366.     FILE *f;
  1367.  
  1368.     for (;;) {
  1369.         if (mp->pointer == 0 ) {
  1370.             usputs(mp->s,nonext);
  1371.             return 0;
  1372.         }
  1373.         if (++(mp->pointer) > mp->last) {
  1374.             mp->pointer--;
  1375.             usputs(mp->s,nonext);
  1376.             return 0;
  1377.         }
  1378.         sprintf(mp->buf,"%s/%u",mp->path,mp->pointer);
  1379.         if ((f = open_file(mp->buf,READ_TEXT,mp->s,0)) != NULLFILE) {
  1380.             fclose(f);
  1381.             return 1;
  1382.         }
  1383.     }
  1384. }
  1385.  
  1386. /* gets last news of newsgroup
  1387.  * returncode: -1 if error; 0 no news; 1 success */
  1388. static int
  1389. get_last(mp)
  1390. struct nntpsv *mp;
  1391. {
  1392.     FILE *f;
  1393.  
  1394.     for (;;) {
  1395.         if (mp->pointer == 0) {
  1396.             usputs(mp->s,noprev);
  1397.             return 0;
  1398.         }
  1399.         if (--(mp->pointer) < mp->first) {
  1400.             mp->pointer++;
  1401.             usputs(mp->s,noprev);
  1402.             return 0;
  1403.         }
  1404.         sprintf(mp->buf,"%s/%u",mp->path,mp->pointer);
  1405.         if ((f = open_file(mp->buf,READ_TEXT,mp->s,0)) != NULLFILE) {
  1406.             fclose(f);
  1407.             return 1;
  1408.         }
  1409.     }
  1410. }
  1411.  
  1412. static int
  1413. art_ret(mp)
  1414. struct nntpsv *mp;
  1415. {
  1416.     if(get_id(mp->buf,mp) == -1)
  1417.         return -1;
  1418.     return usprintf(mp->s,retrieve,mp->pointer,mp->buf,artmsg);
  1419. }
  1420.  
  1421. static int
  1422. doarticle(buf,mp)   /* Sends article <message-id> to the client */
  1423. char *buf;
  1424. struct nntpsv *mp;
  1425. {
  1426.     FILE *f;
  1427.     char *p, *p2, *holds, line[LineLen];
  1428.  
  1429.     if((p = strchr(buf,'<')) == NULLCHAR
  1430.      || (f = open_file(History,READ_TEXT,mp->s,0)) == NULLFILE)
  1431.         return 0;
  1432.  
  1433.     for(;;) {
  1434.         if (fgets(line,LineLen,f) == NULL)
  1435.             break;
  1436.         if (strstr(line,p) != NULL) {
  1437.             fclose(f);
  1438.  
  1439.             p = (strchr(line,' ')) + 14;      /* point to the first newsgroup */
  1440.             p2 = strchr(p,'/');                  /* point to article number */
  1441.             mp->hold_i = mp->pointer;       /* save current pointer */
  1442.             holds = strdup(mp->path);      /* save path of current article */
  1443.             mp->pointer = atoi((p2 + 1));     /* get the article number */
  1444.  
  1445.             if (mp->path != NULLCHAR) {
  1446.                 free(mp->path);
  1447.                 mp->path='\0';
  1448.             }
  1449.  
  1450.             *p2 = '\0';
  1451.             rip2(p);
  1452.  
  1453.             if (strncmp(p+1,"JUNK",6) == 0) {
  1454.                 sprintf(mp->buf,"%s",Forward);
  1455.                 mp->path = strdup(mp->buf);
  1456.             } else
  1457.                 get_path(p,mp);
  1458.  
  1459.             if ((f = open_message(mp,f)) == NULLFILE) {
  1460.                 usputs(mp->s,error);
  1461.                 return 0;
  1462.             }
  1463.             art_ret(mp);
  1464.             sendfile(f, mp->s, ASCII_TYPE,0);
  1465.             fclose(f);
  1466.             usputs(mp->s,NEol);
  1467.             free(mp->path);
  1468.             mp->path=strdup(holds);
  1469.             mp->pointer=mp->hold_i;
  1470.             free(holds);
  1471.             return 1;
  1472.         }
  1473.  
  1474.     }
  1475.     fclose(f);
  1476.     usputs(mp->s,noart);
  1477.     return 0;
  1478. }
  1479.  
  1480. /* checks for a minimum header
  1481.  * returncode: -1 if error; 0 complete; 1 not complete */
  1482. static int
  1483. garbled(f)
  1484. FILE *f;
  1485. {
  1486. /*
  1487.  * The minimum requirement for an incoming article is that it must have
  1488.  * a newsgroups: line, a message-id: line, and a blank line.  This is
  1489.  * pretty forgiving.
  1490.  */
  1491.     char line[LineLen];
  1492.     int ok = 0;
  1493.  
  1494.     rewind(f);
  1495.     for(;;) {
  1496.         if (fgets(line,LineLen,f) == NULL)
  1497.             break;
  1498.         if (strnicmp(line,Hdrs[NEWSGROUPS],12) == 0)
  1499.             ok |= 1;
  1500.         if (strnicmp(line,Hdrs[MSGID],12) == 0)
  1501.             ok |= 2;
  1502.         if (ok == 3)
  1503.             break;
  1504.         if (check_blank(line))
  1505.             break;
  1506.     }
  1507.     rewind(f);
  1508.     return (ok == 3) ? 0 : 1;
  1509. }
  1510.  
  1511. /* returncode: -1 if error; 0 success */
  1512. static int
  1513. get_article2(mp, id)
  1514. struct nntpsv *mp;
  1515. char *id;
  1516. {
  1517.     FILE *f;
  1518.     int ret = -1;
  1519.  
  1520.     if((f = temp_file(0,1)) == NULLFILE)
  1521.         return -1;
  1522.  
  1523.     mp->ap = (struct article *)callocw(1,sizeof(struct article));
  1524.     mp->id = strdup(id);
  1525.     usputs(mp->s,sendart);
  1526.  
  1527.     if(recv_file(f,mp->s) == -1)
  1528.         goto quit;
  1529.  
  1530.     if ((ret = garbled(f)) != 0) {
  1531.         usputs(mp->s,transnotok);
  1532.         goto quit;
  1533.     }
  1534.     if(xfer_article2(f,mp) == 0)
  1535.         goto quit;
  1536.     usputs(mp->s,transok);
  1537.  
  1538. /*     free_ap(mp);             <------------ */
  1539. quit:
  1540. /*  free((char *)mp->ap);  <------------ */
  1541.     free(mp->id);
  1542.     fclose(f);
  1543.     return ret;
  1544. }
  1545.  
  1546. void
  1547. poll(p)
  1548. void *p;
  1549. {
  1550.     newproc("NNTP Client", 2048, nntppoll, 0, p, NULL, 0);
  1551. }
  1552.  
  1553. static void
  1554. nntpserv(s,unused,p)
  1555. int s;
  1556. void *unused;
  1557. void *p;
  1558. {
  1559.     struct nntpsv *mp;
  1560.     FILE *fp;
  1561.     long t;
  1562.     int cnt;
  1563.     char **cmdp, *arg, *cp, *cmd, buf[LineLen];
  1564.  
  1565.     sockmode(s,SOCK_ASCII);
  1566.     sockowner(s,Curproc);        /* We own it now */
  1567.     log(s,"open NNTP");
  1568.  
  1569.     if (!Filecheck)
  1570.         if(check_system()) {
  1571.             usprintf(s,fatal,"STRUCTURE");
  1572.             log(s,"NNTP error - FILE STRU");
  1573.             close_s(s);
  1574.             return;
  1575.         }
  1576.     if((mp = (struct nntpsv *)callocw(1,sizeof(struct nntpsv))) == NULLNNTPSV) {
  1577.         usprintf(s,Nospace);
  1578.         close_s(s);
  1579.         return;
  1580.     }
  1581.     mp->s = s;
  1582.     mp->debug = 0;
  1583.     mp->path = NULLCHAR;
  1584.  
  1585.     time(&t);
  1586.     cp = ctime(&t);
  1587.     cp[24] = '\0';
  1588.  
  1589.     usprintf(s,nnversion,(Filecheck) ? "0" : "1",Host,Version,cp);
  1590.  
  1591. loop:
  1592.     if ((cnt = recvline(s,buf,LineLen)) == -1) {
  1593.         /* He closed on us */
  1594.         goto quit;
  1595.     }
  1596.     rip2(buf);
  1597.     cmd = buf;
  1598.  
  1599.     /* Translate entire buffer to lower case */
  1600.     for(cp = cmd; *cp != '\0' ;cp++) {
  1601.         if ( *cp == ' ' ) break;
  1602.         *cp = tolower(*cp);
  1603.     }
  1604.     /* Find command in table; if not present, return syntax error */
  1605.     for(cmdp = commands; *cmdp != NULLCHAR; cmdp++)
  1606.         if(strnicmp(*cmdp,cmd,min(strlen(*cmdp),strlen(cmd))) == 0)
  1607.             break;
  1608.  
  1609.     if(*cmdp == NULLCHAR){
  1610.         usputs(mp->s,badsyntax);
  1611.         goto loop;
  1612.     }
  1613.     arg = &cmd[strlen(*cmdp)];
  1614.  
  1615.     /* Skip spaces after command */
  1616.     while(*arg == ' ')
  1617.         arg++;
  1618.  
  1619.     /* Execute specific command */
  1620.     switch(cmdp - commands) {
  1621.     case QUIT_CMD:
  1622.         goto quit;
  1623.     case NEWNEWS_CMD:
  1624.         if ((cp = strchr(buf,' ')) == NULLCHAR) {
  1625.             usputs(mp->s,badsyntax);
  1626.             break;
  1627.         }
  1628.         cp++;
  1629.         donewnews(cp,mp);
  1630.         break;
  1631.     case IHAVE_CMD:
  1632.         if ((cp = strchr(buf,'<')) == NULLCHAR) {
  1633.             usputs(mp->s,badsyntax);
  1634.             break;
  1635.         }
  1636.         if (check_article(cp) == 1) {
  1637.             usputs(mp->s,notwanted);
  1638.             break;
  1639.         }
  1640.         if(get_article2(mp,cp))
  1641.             goto quit;
  1642.         break;
  1643.     case HELP_CMD:
  1644.         usprintf(mp->s,"100 %s - help follows:\n",Host);
  1645.         if ((fp = open_file(Nhelp,READ_TEXT,0,0)) != NULLFILE ) {
  1646.             sendfile(fp,mp->s,ASCII_TYPE,0);
  1647.             fclose(fp);
  1648.         } else {
  1649.             usputs(mp->s,help);
  1650.         }
  1651.         usputs(mp->s,NEol);
  1652.         break;
  1653.     case XINFO_CMD:
  1654.         if ((fp = open_file(NInfo,READ_TEXT,0,0)) != NULLFILE ) {
  1655.             usprintf(mp->s,"100 %s - xinfo follows:\n",Host);
  1656.             sendfile(fp,mp->s,ASCII_TYPE,0);
  1657.             fclose(fp);
  1658.         } else {
  1659.             usputs(mp->s,xinfo);
  1660.         }
  1661.         usputs(mp->s,NEol);
  1662.         break;
  1663.     case LIST_CMD:
  1664.         if ((fp = open_file(Active,READ_TEXT,mp->s,0)) != NULLFILE) {
  1665.             sendfile(fp,mp->s,ASCII_TYPE,0);
  1666.             fclose(fp);
  1667.             usputs(mp->s,NEol);
  1668.         }
  1669.         break;
  1670.     case GROUP_CMD :
  1671.         dogroup(mp,&buf[0]);
  1672.         break;
  1673.     case HEAD_CMD : {
  1674.         if (check_grp(mp))
  1675.             break;
  1676.         if (get_id(mp->buf,mp) == 0)
  1677.             break;
  1678.         usprintf(mp->s,head,mp->pointer,mp->buf,artmsg);
  1679.         if ((fp = open_message(mp,fp)) == NULLFILE)
  1680.             break;
  1681.         for (;;) {
  1682.             if ((fgets(mp->buf,LineLen,fp)) == NULL)
  1683.                 break;
  1684.             if (check_blank(mp->buf))
  1685.                 break;
  1686.             usprintf(mp->s,"%s",mp->buf);
  1687.         }
  1688.         fclose(fp);
  1689.         usputs(mp->s,NEol);
  1690.         break;
  1691.     }
  1692.     case BODY_CMD : {
  1693.         if (check_grp(mp))
  1694.             break;
  1695.         if (get_id(mp->buf,mp) == 0)
  1696.             break;
  1697.         usprintf(mp->s,body,mp->pointer,mp->buf,artmsg);
  1698.         if ((fp = open_message(mp,fp)) == NULLFILE)
  1699.             break;
  1700.         mp->hold_i = 0;
  1701.         for (;;) {
  1702.             if ((fgets(mp->buf,LineLen,fp)) == NULL)
  1703.                 break;
  1704.             if (mp->hold_i)
  1705.                 usputs(mp->s,mp->buf);
  1706.             if (check_blank(mp->buf))
  1707.                 mp->hold_i = 1;
  1708.         }
  1709.         fclose(fp);
  1710.         usputs(mp->s,NEol);
  1711.         break;
  1712.     }
  1713.     case STAT_CMD : {
  1714.         if (check_grp(mp))
  1715.             break;
  1716.         if (get_id(mp->buf,mp) == 0)
  1717.             break;
  1718.         usprintf(mp->s,statistics,mp->pointer,mp->buf,artmsg);
  1719.         break;
  1720.     }
  1721.     case ARTICLE_CMD : {
  1722.         if (strchr(buf,'<') != NULLCHAR) {
  1723.           doarticle(buf,mp);
  1724.           break;
  1725.         }
  1726.         if (check_grp(mp))
  1727.             break;
  1728.         cp = strchr(buf,'e');
  1729.         cp++;
  1730.         if ((cnt < 9 ) || (check_blank(cp))) {
  1731.             if ((fp = open_message(mp,fp)) == NULLFILE)
  1732.                 break;
  1733.             art_ret(mp);
  1734.             sendfile(fp,mp->s,ASCII_TYPE,0);
  1735.             fclose(fp);
  1736.             usputs(mp->s,NEol);
  1737.             break;
  1738.         }
  1739.         if ((cp = strpbrk(buf,"0123456789")) != NULLCHAR) {
  1740.             cnt = atoi(cp);
  1741.             if ((cnt > mp->last) || ( cnt < mp->first)) {
  1742.                 usputs(mp->s,noart);
  1743.                 break;
  1744.             }
  1745.             mp->pointer = cnt;
  1746.             if ((fp = open_message(mp,fp)) == NULLFILE)
  1747.                 break;
  1748.             art_ret(mp);
  1749.             sendfile(fp,mp->s,ASCII_TYPE,0);
  1750.             fclose(fp);
  1751.             usputs(mp->s,NEol);
  1752.             break;
  1753.         }
  1754.         break;
  1755.     }
  1756.     case NEXT_CMD : {
  1757.         if (check_grp(mp))
  1758.             break;
  1759.         if (get_next(mp) == 1) {
  1760.             if (get_id(buf,mp) == 1)
  1761.                 usprintf(mp->s,sepcmd,mp->pointer,&buf[1],artmsg);
  1762.             break;
  1763.         }
  1764.         break;
  1765.     }
  1766.     case LAST_CMD :
  1767.         if (check_grp(mp))
  1768.             break;
  1769.         if (get_last(mp) == 1 ) {
  1770.             if (get_id(buf,mp) == 1)
  1771.                 usprintf(mp->s,sepcmd,mp->pointer,&buf[1],artmsg);
  1772.             break;
  1773.         }
  1774.         break;
  1775.     /* This two following cmds currently are not used for much */
  1776.     case DEBUG_CMD:
  1777.         mp->debug = (mp->debug == 0) ? 1 : 0;
  1778.         usprintf(mp->s,debug,(mp->debug == 0) ? "OFF" : "ON");
  1779.         break;
  1780.     case SLAVE_CMD :
  1781.         mp->slave = (mp->slave == 0) ? 1 : 0;
  1782.         usprintf(mp->s,slave,(mp->slave == 0) ? "OFF" : "ON");
  1783.         break;
  1784.     }
  1785.     goto loop;
  1786.  
  1787. quit:
  1788.     usputs(mp->s,closing);
  1789.     log(mp->s,"close NNTP");
  1790.     close_s(mp->s);
  1791.     if(mp->path != NULLCHAR)
  1792.         free(mp->path);
  1793.     if(mp->newnews != NULLCHAR)
  1794.         free(mp->newnews);
  1795.     if(mp->fname != NULLCHAR)
  1796.         free(mp->fname);
  1797.     if(mp->id != NULLCHAR);
  1798.         free(mp->id);
  1799.     free((char *)mp);
  1800. }
  1801.  
  1802. /* ---------------------------- NNTP-GATE --------------------------- */
  1803.  
  1804. static char * near
  1805. mkreplypath(FILE *data)
  1806. {
  1807.     char buf[LINELEN], *cp, *cp1, *path;
  1808.  
  1809.     sprintf(buf,"%sNNTP_GATE@%s",Hdrs[PATH],Hostname);
  1810.     path = strdup(buf);
  1811.     rewind(data);
  1812.     while((fgets(buf,LINELEN,data)) != 0) {
  1813.         if(htype(buf) == DATE)
  1814.             break;
  1815.         if(htype(buf) == RECEIVED) {
  1816.             cp = strchr(buf,' ');
  1817.             cp++;
  1818.             cp = strchr(cp, ' ');
  1819.             cp++;
  1820.             cp1 = strpbrk(cp, ". \0");
  1821.             *cp1 = '\0';
  1822.             cp1 = mallocw(strlen(path)+strlen(cp)+2);  /* */
  1823.             sprintf(cp1,"%s!%s",path,cp);
  1824.             free(path);
  1825.             path = cp1;
  1826.         }
  1827.     }
  1828.     return(path);
  1829. }
  1830.  
  1831. int
  1832. nnGpost(FILE *data,char *from,struct list *le)
  1833. {
  1834.     struct nntpsv *mp;
  1835.     char buf[LINELEN], *cp;
  1836.     FILE *f, *idf;
  1837.     int32 id;
  1838.     long currtime;
  1839.  
  1840.     if (!Filecheck)
  1841.         if(check_system())
  1842.             return -1;
  1843.  
  1844.     if ((f = temp_file(0,1)) == NULLFILE)
  1845.         return -1;
  1846.  
  1847.     mp = (struct nntpsv *)callocw(1,sizeof(struct nntpsv));
  1848.  
  1849.     /* build postuser */
  1850.     cp = mkreplypath(data);
  1851.     fprintf(f,"%s\n",cp);
  1852.     free((char *)cp);
  1853.     fprintf(f,"%s%s\n",Hdrs[FROM],from);
  1854.     /*----------------------------------------------------------------*
  1855.     * build newsgroup                                                 *
  1856.     *-----------------------------------------------------------------*/
  1857.     if((cp = strchr(le->val,'@')) != NULLCHAR)
  1858.         *cp = '\0';
  1859.     fprintf(f,"%s%s\n",Hdrs[NEWSGROUPS],&le->val[1]);          /* skip the bang */
  1860.     /*----------------------------------------------------------------*
  1861.     * find the subject
  1862.     *-----------------------------------------------------------------*/
  1863.     rewind (data);
  1864.     while((fgets(buf,sizeof(buf),data))!=0)   {
  1865.         if (htype(buf)== SUBJECT)
  1866.             break;
  1867.         continue;
  1868.     }
  1869.     fputs((*buf == 0) ? "Subject: (none)\n" : buf,f);
  1870.     /*-------------------------------------------------------------------*
  1871.     * use msgid of original message
  1872.     *--------------------------------------------------------------------*/
  1873.     rewind(data);
  1874.     while((fgets(buf,sizeof(buf),data))!=0)   {
  1875.         if (htype(buf)== MSGID)
  1876.             break;
  1877.         continue;
  1878.     }
  1879.     if (*buf == 0)   {
  1880.         sprintf(buf,"%s/sequence.seq",Mailqdir);
  1881.         idf = open_file(buf,"r+",0,1);
  1882.         id = atol(fgets(buf,LineLen,idf));
  1883.         rewind(idf);
  1884.         fprintf(idf,"%ld",id+2);
  1885.         fclose(idf);
  1886.         fprintf(f,"%s<%ld@%s>\n",Hdrs[MSGID],id,Hostname);
  1887.         sprintf(mp->buf,"<%ld@%s>",id,Hostname);
  1888.     } else {
  1889.         fputs(buf,f);
  1890.         rip(buf);
  1891.         cp = strchr(buf,'<');
  1892.         strcpy(mp->buf,cp);
  1893.         if (check_article(mp->buf))
  1894.             goto quit;
  1895.     }
  1896.     rewind (data);
  1897.     time(&currtime);
  1898.     fprintf(f,"Sender: NNTP@%s\n",Hostname);
  1899.     /*-------------------------------------------------------------------*
  1900.     * message follows                                                    *
  1901.     *--------------------------------------------------------------------*/
  1902.     fputs("Comments: Message transferred from SMTP\n",f);
  1903.     while((fgets(buf,sizeof(buf),data))!=0)   {
  1904.         switch(htype(buf))   {
  1905.             case FROM:
  1906.             case MSGID:
  1907.             case RECEIVED:
  1908.                 fgets(buf,sizeof(buf),data); /*eat the id*/
  1909.                 continue;
  1910.         }
  1911.         fputs(buf,f);
  1912.     }
  1913.     rewind(f);
  1914.     mp->id = strdup(mp->buf);
  1915.     xfer_article2(f,mp);
  1916. /*
  1917.     log(-1,"NNGT: transfer: Msg %s",mp->id);
  1918. */
  1919. quit:
  1920.     fclose(f);
  1921.     free(mp);
  1922.     return 0;
  1923. }
  1924.  
  1925. /* ---------------------------- Servercmd --------------------------- */
  1926.  
  1927. /* Start up NNTP receiver service */
  1928. int
  1929. nntp1(argc,argv,p)
  1930. int argc;
  1931. char *argv[];
  1932. void *p;
  1933. {
  1934.     struct sockaddr_in lsocket;
  1935.     int s;
  1936.  
  1937.     if(Snntp != -1)
  1938.         return -1;
  1939.     if(check_system() == -1)
  1940.         return -1;
  1941.  
  1942.     psignal(Curproc,0);    /* Don't keep the parser waiting */
  1943.     chname(Curproc,"NNTP listener");
  1944.  
  1945.     lsocket.sin_family = AF_INET;
  1946.     lsocket.sin_addr.s_addr = INADDR_ANY;
  1947.     lsocket.sin_port = (argc < 2) ? IPPORT_NNTP : atoi(argv[1]);
  1948.  
  1949.     Snntp = socket(AF_INET,SOCK_STREAM,0);
  1950.     bind(Snntp,(char *)&lsocket,sizeof(lsocket));
  1951.     listen(Snntp,1);
  1952.  
  1953.     for(;;){
  1954.         if((s = accept(Snntp,NULLCHAR,(int *)NULL)) == -1)
  1955.             break;    /* Service is shutting down */
  1956.  
  1957.         /* Low mem check now done in tcpin.c - WG7J */
  1958.         sockmode(s,SOCK_ASCII);
  1959.         /* Spawn a server */
  1960.         newproc("NNTP server",2048,nntpserv,s,NULL,NULL,0);
  1961.     }
  1962.     return 0;
  1963. }
  1964.  
  1965. /* Shutdown NNTP service (existing connections are allowed to finish) */
  1966. int
  1967. nntp0(argc,argv,p)
  1968. int argc;
  1969. char *argv[];
  1970. void *p;
  1971. {
  1972.     close_s(Snntp);
  1973.     Snntp = -1;
  1974.     return 0;
  1975. }
  1976.  
  1977. /* ---------------------------- Subcmds --------------------------- */
  1978.  
  1979. /* lists active newsgroups
  1980.  * returncode: -1 if error; 0 success */
  1981. static int
  1982. donnactive(argc,argv,p)
  1983. int argc;
  1984. char *argv[];
  1985. void *p;
  1986. {
  1987.     FILE *fp;
  1988.     char line[80], *cp;
  1989.  
  1990.     if((fp = open_file(Active,READ_TEXT,0,1)) == NULLFILE)
  1991.         return -1;
  1992.  
  1993.     tputs("Msg#  next  mod newsgroup\n");
  1994.  
  1995.     for(;;) {
  1996.         if (fgets(line,sizeof(line),fp) == NULL)
  1997.             break;
  1998.         if((cp = strchr(line,' ')) == NULLCHAR)
  1999.             break;
  2000.         *cp = '\0';
  2001.         rip(++cp);
  2002.         tprintf("%s   %s\n",cp,line);
  2003.     }
  2004.     fclose(fp);
  2005.     return 0;
  2006. }
  2007.  
  2008. /* add nntp servers to list */
  2009. static int
  2010. donnadds(argc,argv,p)
  2011. int argc;
  2012. char *argv[];
  2013. void *p;
  2014. {
  2015.     struct Servers *np;
  2016.  
  2017.     for(np = Nntpserver; np != NULLSERVER; np = np->next)
  2018.         if(stricmp(np->name,argv[1]) == 0)
  2019.             break;
  2020.     if (np == NULLSERVER) {
  2021.         np = (struct Servers *)callocw(1,sizeof(struct Servers));
  2022.         if((np->dest = resolve(argv[1])) == 0) {
  2023.             tprintf(Badhost,argv[1]);
  2024.             free((char *)np);
  2025.             return -1;
  2026.         }
  2027.         np->name = strdup(argv[1]);
  2028.         np->next = Nntpserver;
  2029.         Nntpserver = np;
  2030.         np->newsgroups = NULLCHAR;
  2031.         np->lowtime = np->hightime = -1;
  2032.         np->nntpt.func = poll;        /* what to call on timeout */
  2033.         np->nntpt.arg = (void *)np;
  2034.     }
  2035.     if (argc > 3) {
  2036.         int i;
  2037.         if (np->newsgroups == NULLCHAR) {
  2038.             np->newsgroups = callocw(1,LineLen);
  2039.             *np->newsgroups = '\0';
  2040.         }
  2041.         for (i = 3; i < argc; ++i) {
  2042.             if (isdigit(*argv[i])) {
  2043.                 int lh, ll, hh, hl;
  2044.                 sscanf(argv[i], "%d:%d-%d:%d", &lh, &ll, &hh, &hl);
  2045.                 np->lowtime = lh * 100 + ll;
  2046.                 np->hightime = hh * 100 + hl;
  2047.             } else if ((strlen(np->newsgroups)+strlen(argv[i])+2) >= LineLen)
  2048.                 tprintf("To many groups, '%s' ignored\n", argv[i]);
  2049.             else {  /* it's a group, and it fits... add it to list */
  2050.                 if (*np->newsgroups != '\0')
  2051.                     strcat(np->newsgroups, ",");
  2052.                 strcat(np->newsgroups, argv[i]);
  2053.             }
  2054.         }
  2055.         if (*np->newsgroups == '\0') {    /* No groups specified? */
  2056.             free(np->newsgroups);
  2057.             np->newsgroups = NULLCHAR;
  2058.         }
  2059.     }
  2060.     /* set timer duration */
  2061.     set_timer(&np->nntpt,atol(argv[2])*1000L);
  2062.     start_timer(&np->nntpt);        /* and fire it up */
  2063.     return 0;
  2064. }
  2065.  
  2066. /* drops nntp servers from list */
  2067. static int
  2068. donndrops(argc,argv,p)
  2069. int argc;
  2070. char *argv[];
  2071. void *p;
  2072. {
  2073.     struct Servers *np, *npprev = NULLSERVER;
  2074.  
  2075.     for(np = Nntpserver; np != NULLSERVER; npprev = np, np = np->next)
  2076.         if(stricmp(np->name,argv[1]) == 0) {
  2077.             stop_timer(&np->nntpt);
  2078.             free(np->name);
  2079.             if (np->newsgroups)
  2080.                 free(np->newsgroups);
  2081.             if(npprev != NULLSERVER)
  2082.                 npprev->next = np->next;
  2083.             else
  2084.                 Nntpserver = np->next;
  2085.             free((char *)np);
  2086.             return 0;
  2087.     }
  2088.     tputs("No such server enabled.\n");
  2089.     return -1;
  2090. }
  2091.  
  2092. /* copies a news from given newsgroup to the mailbox */
  2093. static int
  2094. donndump(argc,argv,p)
  2095. int argc;
  2096. char *argv[];
  2097. void *p;
  2098. {
  2099.     FILE *t, *f, *o;
  2100.     char path[LineLen], line[LineLen], *cp, newsname[25], *cp1;
  2101.     struct ffblk blk;
  2102.  
  2103.     if (!Filecheck)
  2104.         if(check_system())
  2105.             return -1;
  2106.  
  2107.     if ((f = open_file(Pointer,READ_TEXT,0,1)) == NULLFILE)
  2108.         return 0;
  2109.  
  2110.     path[0] = '\0';
  2111.     line[0] = '\0';
  2112.  
  2113.     for(;;) {
  2114.         if (fgets(line,LineLen,f) == NULL)
  2115.             break;
  2116.         if (!strncmp(line,argv[1],strlen(argv[1]))) {
  2117.             cp = strchr(line,' ') + 1;
  2118.             strcpy(path,cp);
  2119.             break;
  2120.         }
  2121.     }
  2122.     fclose(f);
  2123.  
  2124.     if (path[0] == '\0') {
  2125.         tprintf("No newsgroup %s\n",argv[1]);
  2126.         goto error;
  2127.     }
  2128.  
  2129.     rip2(path);
  2130.     cp = strrchr(path,'/');
  2131.     cp1 = &newsname[0];
  2132.  
  2133.     while(*cp)
  2134.         *(cp1++) = *(cp++);
  2135.     *cp1 = '\0';
  2136.  
  2137.     strcpy(line,path);
  2138.     strcat(line,"/*.*");
  2139.     if(findfirst(line,&blk,0)) {
  2140.         tputs("No news in newsgroup\n");
  2141.         goto error;
  2142.     }
  2143.     if(argc > 2)
  2144.         sprintf(newsname,"/%s",argv[2]);
  2145.  
  2146.     sprintf(line,"%s%s.txt",Mailspool,newsname);
  2147.     if ((o = open_file(line,"a+",0,1)) == NULLFILE)
  2148.         goto error;
  2149.     if(!(mlock(Mailspool,newsname))) {
  2150.         tprintf("Newsgroup dump to %s\n",line);
  2151.         for (;;) {
  2152.             if((t = temp_file(0,1)) == NULLFILE) {
  2153.                 fclose(o);
  2154.                 goto error;
  2155.             }
  2156.             sprintf(line,"%s/%s",path,blk.ff_name);
  2157.             /* Open the article */
  2158.             if ((f = open_file(line,READ_TEXT,0,1)) == NULLFILE) {
  2159.                 fclose(t);
  2160.                 fclose(o);
  2161.                 goto error;
  2162.             }
  2163.             pwait(NULL);
  2164.             tputc('.'); /* One dot/article processed */
  2165.             tflush();
  2166.  
  2167.             for (;;) {
  2168.                 if (fgets(line,LineLen,f) == NULL)
  2169.                     break;
  2170.                 fputs(line,t);
  2171.                 if (!strnicmp(line,Hdrs[FROM],6)) {
  2172.                     cp = strchr(line,' ')+1;
  2173.                     fprintf(o,"From %s",cp);
  2174.                 }
  2175.             }
  2176.             rewind(t);
  2177.             for(;;) {
  2178.                 if (fgets(line,LineLen,t) == NULL)
  2179.                     break;
  2180.                 fputs(line,o);
  2181.             }
  2182.             fputc('\n',o);
  2183.             fclose(t);
  2184.             fclose(f);
  2185.             if (findnext(&blk))
  2186.                 break;
  2187.         }
  2188.         rmlock(Mailspool,newsname);
  2189.     } else
  2190.         tputs("Mailfile is busy, try later");
  2191.     fclose(o);
  2192.     tputs("\n");
  2193.  
  2194. error:
  2195.     return 0;
  2196. }
  2197.  
  2198. static int
  2199. donnkick(argc,argv,p)
  2200. int argc;
  2201. char *argv[];
  2202. void *p;
  2203. {
  2204.     struct Servers *np;
  2205.  
  2206.     for(np = Nntpserver; np != NULLSERVER; np = np->next)
  2207.         if(!stricmp(np->name,argv[1])) {
  2208.             /* If the timer is not running, the timeout function has
  2209.              * already been called and we don't want to call it again.
  2210.              */
  2211.             if(run_timer(&np->nntpt) || dur_timer(&np->nntpt) == 0) {
  2212.                 stop_timer(&np->nntpt);
  2213.                 poll((void *)np);
  2214.             }
  2215.         return 0;
  2216.     }
  2217.     tputs("No server enabled\n");
  2218.     return 0;
  2219. }
  2220.  
  2221. /* list nntp servers */
  2222. static int
  2223. donnlists(argc,argv,p)
  2224. int argc;
  2225. char *argv[];
  2226. void *p;
  2227. {
  2228.     struct Servers *np;
  2229.     char tbuf[80];
  2230.  
  2231.     for(np = Nntpserver; np != NULLSERVER; np = np->next) {
  2232.         if (np->lowtime != -1 && np->hightime != -1)
  2233.             sprintf(tbuf, " -- %02d:%02d-%02d:%02d",
  2234.                 np->lowtime/100, np->lowtime%100,
  2235.                 np->hightime/100, np->hightime%100);
  2236.         else
  2237.             tbuf[0] = '\0';
  2238.         tprintf("%-32s (%lu/%lu%s)\n   Groups: %s\n", np->name,
  2239.             read_timer(&np->nntpt) /1000L,
  2240.             dur_timer(&np->nntpt) /1000L,
  2241.             tbuf, np->newsgroups ? np->newsgroups : "");
  2242.     }
  2243.     return 0;
  2244. }
  2245.  
  2246. /* manually entering new news
  2247.  * returncode: -1 if error; 0 success */
  2248. static int
  2249. donnpost(argc,argv,p)
  2250. int argc;
  2251. char *argv[];
  2252. void *p;
  2253. {
  2254.     struct session *sp;
  2255.     struct nntpsv *mp;
  2256.     char buf[LineLen];
  2257.     int id;
  2258.     FILE *f, *idf, *ufp;
  2259.     long currtime;
  2260.  
  2261.     if (!Filecheck)
  2262.         if(check_system())
  2263.             return -1;
  2264.  
  2265.     if((sp = newsession("Post",0,1)) == NULLSESSION)
  2266.         return -1;
  2267.  
  2268.     mp = (struct nntpsv *)callocw(1,sizeof(struct nntpsv));
  2269.  
  2270.     for (;;) {
  2271.         if ((f = temp_file(0,1)) == NULLFILE)
  2272.             goto done;
  2273.  
  2274.         sprintf(buf,"%s/sequence.seq",Mailqdir);
  2275.         if ((idf = open_file(buf,"r+",0,1)) == NULLFILE) {
  2276.             tprintf("Please create %s dir ...\n",Mailqdir);
  2277.             fclose(f);
  2278.             goto done;
  2279.         }
  2280.  
  2281.         id = atoi(fgets(buf,LineLen,idf));
  2282.         rewind(idf);
  2283.         fprintf(idf,"%d",id+2);
  2284.         fclose(idf);
  2285.  
  2286.         if (Post->user == NULLCHAR) {
  2287.             tputs("User name? ");
  2288.             recvline(sp->input,buf,LineLen);
  2289.             rip2(buf);
  2290.             Post->user = strdup(buf);
  2291.         }
  2292.         fprintf(f,"%s%s\n",Hdrs[PATH],Post->user);
  2293.         fprintf(f,"%s%s@%s",Hdrs[FROM],Post->user,Hostname);
  2294.         if (Post->fullname != NULLCHAR)
  2295.             fprintf(f," (%s )",Post->fullname);
  2296.         fputc('\n',f);
  2297.  
  2298.         tputs("Newsgroup? ");
  2299.         recvline(sp->input,buf,LineLen);
  2300.         rip2(buf);
  2301.         if (check_blank(buf))
  2302.             goto done;
  2303.         fprintf(f,"%s%s\n",Hdrs[NEWSGROUPS],buf);
  2304.  
  2305.         tputs("Subject? ");
  2306.         recvline(sp->input,buf,LineLen);
  2307.         fprintf(f,"%s%s",Hdrs[SUBJECT],buf);
  2308.         fprintf(f,"%s<%d@%s>\n",Hdrs[MSGID],id,Hostname);
  2309.         time(&currtime);
  2310.         fprintf(f,"Date: %s",ptime(&currtime));
  2311.         fprintf(f,"Sender: NNTP@%s\n",Hostname);
  2312.  
  2313.         if (Post->reply != NULLCHAR)
  2314.             fprintf(f,"%s%s\n",Hdrs[REPLYTO],Post->reply);
  2315.  
  2316.         if (Post->organ != NULLCHAR)
  2317.             fprintf(f,"Organization: %s\n",Post->organ);
  2318.  
  2319.         fputc('\n',f);
  2320.         tputs("Enter message - end with .\n");
  2321.  
  2322.         for (;;) {
  2323.             recvline(sp->input,buf,LineLen);
  2324.             if(strcmp(buf,".u\n") == 0
  2325.               || strcmp(buf,".r\n") == 0) {
  2326.                 tputs("Filename? ");
  2327.                 recvline(sp->input,buf,LineLen);
  2328.                 rip2(buf);
  2329.                 if((ufp = open_file(buf,READ_TEXT,0,1)) != NULLFILE) {
  2330.                     while(fgets(buf,LineLen,ufp) != NULL)
  2331.                         fputs(buf,f);
  2332.                     fclose(ufp);
  2333.                 }
  2334.                 tputs("(continue)\n");
  2335.             }
  2336.             if(strcmp(buf,".\n") == 0
  2337.               || strcmpi(buf,"***END\n") == 0
  2338.               || strcmpi(buf,"/EX\n") == 0)
  2339.                 break;
  2340.             fputs(buf,f);
  2341.         }
  2342.  
  2343.         if (Post->sig != NULLCHAR) {
  2344.             sprintf(buf,"%s",Post->sig);
  2345.             if ((idf = open_file(buf,READ_TEXT,0,1)) != NULLFILE ) {
  2346.                 while(fgets(buf,LineLen,idf) != NULL)
  2347.                     fputs(buf,f);
  2348.                 fclose(idf);
  2349.             }
  2350.         }
  2351.  
  2352. loop:   tputs("\n[Send, Abort, Exit, List] ");
  2353.         recvline(sp->input,buf,LineLen);
  2354.         switch(tolower(buf[0])) {
  2355.         case 's':
  2356.             rewind(f);
  2357.             sprintf(mp->buf,"<%d@%s>",id,Hostname);
  2358.             mp->id = strdup(mp->buf);
  2359.             xfer_article2(f,mp);
  2360.             break;
  2361.         case 'l':
  2362.             rewind(f);
  2363.             for(;;) {
  2364.                 if (fgets(buf,LineLen,f) == NULL)
  2365.                     break;
  2366.                 tputs(buf);
  2367.             }
  2368.             rewind(f);
  2369.             goto loop;
  2370.         case 'e':
  2371.             fclose(f);
  2372.             goto done;
  2373.         case 'a':
  2374.             break;
  2375.         default:
  2376.             goto loop;
  2377.         }
  2378.         fclose(f);
  2379.         tputs("Post another? ");
  2380.         recvline(sp->input,buf,LineLen);
  2381.         if (tolower(buf[0]) == 'n')
  2382.             goto done;
  2383.     }
  2384.  
  2385. done:
  2386.     if(f != NULLFILE)
  2387.         fclose(f);
  2388.     keywait(NULLCHAR,1);
  2389.     free((char *) mp);
  2390.     freesession(sp);
  2391.     return 0;
  2392. }
  2393.  
  2394. static int
  2395. donnquiet(argc,argv,p)
  2396. int argc;
  2397. char *argv[];
  2398. void *p;
  2399. {
  2400.     return setintrc(&Nntpquiet,"NNTP quiet",argc,argv,0,2);
  2401. }
  2402.  
  2403. /* -------------------- Profile subcmds -------------------- */
  2404.  
  2405. static int
  2406. donnuser(argc,argv,p)
  2407. int argc;
  2408. char *argv[];
  2409. void *p;
  2410. {
  2411.     if(argc < 2 && Post->user != NULLCHAR)
  2412.         tprintf("%s\n",Post->user);
  2413.     else {
  2414.         free(Post->user);
  2415.         Post->user = strdup(argv[1]);
  2416.     }
  2417.     return 0;
  2418. }
  2419.  
  2420. static int
  2421. donnsig(argc,argv,p)
  2422. int argc;
  2423. char *argv[];
  2424. void *p;
  2425. {
  2426.     if(argc < 2 && Post->sig != NULLCHAR)
  2427.         tprintf("%s\n",Post->sig);
  2428.     else {
  2429.         if(access(argv[1],0) == 0) {
  2430.             free(Post->sig);
  2431.             Post->sig = strdup(argv[1]);
  2432.         } else {
  2433.             tputs("No such signature file\n");
  2434.             return -1;
  2435.         }
  2436.     }
  2437.     return 0;
  2438. }
  2439.  
  2440. static int
  2441. donnfull(argc,argv,p)
  2442. int argc;
  2443. char *argv[];
  2444. void *p;
  2445. {
  2446.     if(argc < 2 && Post->fullname != NULLCHAR)
  2447.         tprintf("%s\n",Post->fullname);
  2448.     else {
  2449.         free(Post->fullname);
  2450.         Post->fullname = strdup(argv[1]);
  2451.     }
  2452.     return 0;
  2453. }
  2454.  
  2455. static int
  2456. donnhost(argc,argv,p)
  2457. int argc;
  2458. char *argv[];
  2459. void *p;
  2460. {
  2461.     if(argc < 2 && Host != NULLCHAR)
  2462.         tprintf("%s\n",Host);
  2463.     else {
  2464.         free(Host);
  2465.         Host = strdup(argv[1]);
  2466.     }
  2467.     return 0;
  2468. }
  2469.  
  2470. static int
  2471. donnorgan(argc,argv,p)
  2472. int argc;
  2473. char *argv[];
  2474. void *p;
  2475. {
  2476.     if(argc < 2 && Post->organ != NULLCHAR)
  2477.         tprintf("%s\n",Post->organ);
  2478.     else {
  2479.         free(Post->organ);
  2480.         Post->organ = strdup(argv[1]);
  2481.     }
  2482.     return 0;
  2483. }
  2484.  
  2485. static int
  2486. donnreply(argc,argv,p)
  2487. int argc;
  2488. char *argv[];
  2489. void *p;
  2490. {
  2491.     if(argc < 2 && Post->reply != NULLCHAR)
  2492.         tprintf("%s\n",Post->reply);
  2493.     else {
  2494.         free(Post->reply);
  2495.         Post->reply = strdup(argv[1]);
  2496.     }
  2497.     return 0;
  2498. }
  2499.  
  2500. /* subcmd parser */
  2501. static int
  2502. donnprofile(argc,argv,p)
  2503. int argc;
  2504. char *argv[];
  2505. void *p;
  2506. {
  2507.     struct cmds Prof[] = {
  2508.         "fullname",    donnfull,    0, 0, NULLCHAR,
  2509.         "host",        donnhost,    0, 0, NULLCHAR,
  2510.         "organ",    donnorgan,    0, 0, NULLCHAR,
  2511.         "reply",    donnreply,    0, 0, NULLCHAR,
  2512.         "sig",        donnsig,     0, 0, NULLCHAR,
  2513.         "user",        donnuser,    0, 0, NULLCHAR,
  2514.         NULLCHAR,
  2515.     };
  2516.     if(Post == NULLPOST) {
  2517.         Post = (struct post *)callocw(1,sizeof(struct post));
  2518.         Post->user = Post->reply = Post->sig = Post->organ = Post->fullname = NULLCHAR;
  2519.     }
  2520.     if (Host == NULLCHAR) {
  2521.         Host = strdup(Hostname);
  2522.     }
  2523.     return (argc == 10) ? 0 : (subcmd(Prof,argc,argv,p));
  2524. }
  2525.  
  2526. /* cmd parser */
  2527. int
  2528. donntp(argc,argv,p)
  2529. int argc;
  2530. char *argv[];
  2531. void *p;
  2532. {
  2533.     struct cmds Nntp[] = {
  2534.         "active",    donnactive,        0,       0, NULLCHAR,
  2535.         "add",        donnadds,        0,       3, "nntp add <nntpserv> <interval> [<groups>]",
  2536.         "drop",        donndrops,        0,       2, "nntp drop <nntpserv>",
  2537.         "dump",     donndump,         0,       2, "nntp dump <newsgroup> [<mailbox>]",
  2538.         "kick",     donnkick,         0,       2, "nntp kick <server>",
  2539.         "list",        donnlists,        0,       0, NULLCHAR,
  2540.         "post",     donnpost,         2024, 0, NULLCHAR,
  2541.         "profile",    donnprofile,    0,       0, NULLCHAR,
  2542.         "quite",    donnquiet,        0,      0, NULLCHAR,
  2543.         NULLCHAR,
  2544.     };
  2545.  
  2546.     return (subcmd(Nntp,argc,argv,p));
  2547. }
  2548.  
  2549. /* main file-opening routine
  2550.  * options: s = socketnumber, if given an error msg is printed to the socket
  2551.  * returncode: NULLFILE if error; filepointer success
  2552.  */
  2553. FILE *
  2554. open_file(name,mode,s,t)
  2555. char *name;
  2556. char *mode;
  2557. int s;
  2558. int t;
  2559. {
  2560.     FILE *f;
  2561.     register char *cp;
  2562.  
  2563.     if(name == NULLCHAR || mode == NULLCHAR)
  2564.         return NULLFILE;
  2565. #ifdef MSDOS
  2566.     while((cp = strchr(name,'\\')) != NULLCHAR)
  2567.         *cp = '/';
  2568. #endif
  2569.     if((f = fopen(name,mode)) == NULLFILE) {
  2570.         if(s)
  2571.             usprintf(s,fatal,"",name);
  2572.         if(t)
  2573.             tprintf("Can't open %s: %s\n",name,strerror(errno));
  2574.     }
  2575.     return f;
  2576. }
  2577.  
  2578. /* main tempfile-opening routine
  2579.  * returncode: NULLFILE if error; filepointer success
  2580.  */
  2581. FILE *
  2582. temp_file(s,t)
  2583. int s;
  2584. int t;
  2585. {
  2586.     FILE *f;
  2587.  
  2588.     if((f = tmpfile()) == NULLFILE) {
  2589.         if(s)
  2590.             usprintf(s,fatal,"TMP","");
  2591.         if(t) {
  2592.             tprintf("Can't open TMP: %s\n",strerror(errno));
  2593.         }
  2594.     }
  2595.     return f;
  2596. }
  2597.  
  2598. /* Subroutine for setting and displaying int variables (with range check) */
  2599. int
  2600. setintrc(var, label, argc, argv, minval, maxval)
  2601. int16 *var;
  2602. char *label;
  2603. int argc;
  2604. char *argv[];
  2605. int minval;
  2606. int16 maxval;
  2607. {
  2608.     int tmp;
  2609.  
  2610.     if (argc < 2)
  2611.         tprintf("%s: %u\n", label, *var);
  2612.     else {
  2613.         tmp = atoi(argv[1]);
  2614.         if (isalpha(*argv[1]) || tmp < minval || tmp > maxval) {
  2615.             tprintf("%s must be %i..%i\n", label, minval, maxval);
  2616.             return 1;
  2617.         }
  2618.         *var = (int16)tmp;
  2619.     }
  2620.     return 0;
  2621. }
  2622. #endif /* NNTPS */
  2623.  
  2624.